package com.yeskery.nut.aop;

import java.lang.reflect.Method;
import java.util.List;

/**
 * Around注解的方法处理器执行链对象
 * @author sprout
 * @version 1.0
 * 2023-04-22 12:58
 */
public class AroundProxyMethodHandlerExecutionChain implements Invocation {

    /** 环绕注解执行对象集合 */
    private final List<AroundExecution> aroundList;

    /** 环绕处理器目标方法执行接口 */
    private final Invocation invocation;

    /** 当前执行链索引 */
    private int index = 0;

    /**
     * 构建Around注解的方法处理器执行链对象
     * @param aroundList 环绕注解执行对象集合
     * @param invocation 环绕处理器目标方法执行接口
     */
    public AroundProxyMethodHandlerExecutionChain(List<AroundExecution> aroundList, Invocation invocation) {
        this.aroundList = aroundList;
        this.invocation = invocation;
    }

    @Override
    public Object invoke() {
        while (index < aroundList.size()) {
            AroundExecution aroundExecution = aroundList.get(index);
            try {
                index++;
                Method method = aroundExecution.getMethod();
                if (method.getParameterCount() <= 0) {
                    method.invoke(aroundExecution.getTarget());
                } else {
                    method.invoke(aroundExecution.getTarget(), this);
                }
            } catch (Exception e) {
                Throwable throwable;
                if ((throwable = e.getCause()) != null && throwable.getClass().equals(ProxyAroundAopOriginalInvokeException.class)) {
                    throw (ProxyAroundAopOriginalInvokeException) throwable;
                }
                throw new ProxyObjectExecuteException("@Around Target :[" + aroundExecution.getTarget().getClass().getName()
                        + "] Execute Fail.", e);
            }
        }
        try {
            return invocation.invoke();
        } catch (Exception e) {
            throw new ProxyAroundAopOriginalInvokeException(e);
        }
    }

    @Override
    public ExecutionMetadata getExecutionMetadata() {
        return invocation.getExecutionMetadata();
    }
}
